/*#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include "preprocess.h"
#include "grouping.h"
#include "matching.h"
#include "generation.h"

// 日志记录结构
typedef struct {
    char* original_log;
    int group_id;
    int template_index;
} LogRecord;

typedef struct {
    LogRecord* records;
    uint32_t count;
    uint32_t capacity;
} LogRecords;

// CSV 转义辅助函数
char* escape_csv(const char* str) {
    if (!str) return NULL;
    
    // 检查是否需要转义（包含逗号、双引号或换行符）
    int needs_escaping = 0;
    for (const char* p = str; *p; p++) {
        if (*p == '"' || *p == ',' || *p == '\n' || *p == '\r') {
            needs_escaping = 1;
            break;
        }
    }
    
    if (!needs_escaping) return NULL;
    
    // 计算需要转义的字符数
    int escape_count = 0;
    for (const char* p = str; *p; p++) {
        if (*p == '"') escape_count++;
    }
    
    // 分配足够的内存（原始长度 + 转义字符数 + 引号）
    char* result = malloc(strlen(str) + escape_count + 3);
    if (!result) return NULL;
    
    char* dst = result;
    *dst++ = '"';
    
    for (const char* p = str; *p; p++) {
        if (*p == '"') {
            *dst++ = '"';
            *dst++ = '"';
        } else {
            *dst++ = *p;
        }
    }
    
    *dst++ = '"';
    *dst = '\0';
    
    return result;
}

// 获取组表中的组数量
uint32_t get_group_table_size(const GroupTable* table) {
    return table->group_count;
}

// 获取指定索引的组
TemplateGroup* get_group_from_table(const GroupTable* table, uint32_t index) {
    if (index >= table->group_count) return NULL;
    return table->groups[index];
}

// 模板与日志的映射结构
typedef struct {
    char* group_key;
    char* template_str;
    char** matched_logs;
    uint32_t log_count;
    uint32_t log_capacity;
} TemplateWithLogs;

// 创建模板与日志的映射
TemplateWithLogs* create_template_logs_map(const GroupManager* gm, const LogRecords* log_records, uint32_t* count) {
    // 首先计算需要多少个模板条目
    uint32_t template_count = 0;
    uint32_t group_table_size = get_group_table_size(gm->group_table);
    
    for (uint32_t i = 0; i < group_table_size; i++) {
        TemplateGroup* group = get_group_from_table(gm->group_table, i);
        if (group) {
            template_count += group->template_count;
        }
    }
    
    // 分配内存
    TemplateWithLogs* map = malloc(template_count * sizeof(TemplateWithLogs));
    if (!map) return NULL;
    
    // 初始化所有模板条目
    uint32_t index = 0;
    for (uint32_t i = 0; i < group_table_size; i++) {
        TemplateGroup* group = get_group_from_table(gm->group_table, i);
        if (group) {
            for (uint32_t j = 0; j < group->template_count; j++) {
                map[index].group_key = strdup(group->group_key);
                map[index].template_str = strdup(group->templates[j]->template_str);
                map[index].matched_logs = malloc(10 * sizeof(char*)); // 初始容量
                map[index].log_count = 0;
                map[index].log_capacity = 10;
                index++;
            }
        }
    }
    *count = index;
    
    // 遍历所有日志记录，将它们添加到对应的模板中
    for (uint32_t i = 0; i < log_records->count; i++) {
        const LogRecord* record = &log_records->records[i];
        
        // 确保 group_id 有效
        if (record->group_id < 0 || (uint32_t)record->group_id >= group_table_size) {
            continue;
        }
        
        TemplateGroup* group = get_group_from_table(gm->group_table, record->group_id);
        
        if (group && record->template_index >= 0 && (uint32_t)record->template_index < group->template_count) {
            // 找到对应的模板在map中的位置
            uint32_t map_index = 0;
            for (int g = 0; g < record->group_id; g++) {
                TemplateGroup* current_group = get_group_from_table(gm->group_table, g);
                if (current_group) {
                    map_index += current_group->template_count;
                }
            }
            map_index += record->template_index;
            
            // 检查是否需要扩展容量
            if (map[map_index].log_count >= map[map_index].log_capacity) {
                map[map_index].log_capacity *= 2;
                char** new_logs = realloc(map[map_index].matched_logs, 
                                         map[map_index].log_capacity * sizeof(char*));
                if (new_logs) {
                    map[map_index].matched_logs = new_logs;
                }
            }
            
            // 添加日志
            map[map_index].matched_logs[map[map_index].log_count++] = strdup(record->original_log);
        }
    }
    
    return map;
}

// 释放模板日志映射
void free_template_logs_map(TemplateWithLogs* map, uint32_t count) {
    for (uint32_t i = 0; i < count; i++) {
        free(map[i].group_key);
        free(map[i].template_str);
        for (uint32_t j = 0; j < map[i].log_count; j++) {
            free(map[i].matched_logs[j]);
        }
        free(map[i].matched_logs);
    }
    free(map);
}

// 输出 CSV 文件
void write_logs_to_csv(const GroupManager* gm, const LogRecords* log_records, const char* filename) {
    FILE* file = fopen(filename, "w");
    if (!file) {
        perror("Failed to open CSV file");
        return;
    }
    
    // 创建模板-日志映射
    uint32_t template_count = 0;
    TemplateWithLogs* map = create_template_logs_map(gm, log_records, &template_count);
    if (!map) {
        fclose(file);
        return;
    }
    
    // 写入CSV表头
    fprintf(file, "GroupKey,Template,MatchedLogs,LogCount\n");
    
    // 遍历所有模板，输出每个模板及其匹配的日志
    for (uint32_t i = 0; i < template_count; i++) {
        // 转义所有字段，确保CSV格式正确
        char* escaped_group_key = escape_csv(map[i].group_key);
        char* escaped_template = escape_csv(map[i].template_str);
        
        // 创建匹配日志的JSON数组字符串
        char logs_buffer[8192] = "["; // 增加缓冲区大小
        uint32_t buf_pos = 1;
        
        for (uint32_t j = 0; j < map[i].log_count; j++) {
            // 转义每个日志条目
            char* escaped_log = escape_csv(map[i].matched_logs[j]);
            const char* log_to_use = escaped_log ? escaped_log : map[i].matched_logs[j];
            size_t log_len = strlen(log_to_use);
            
            // 检查缓冲区是否足够
            if (buf_pos + log_len + 4 < sizeof(logs_buffer)) {
                if (j > 0) {
                    logs_buffer[buf_pos++] = ',';
                }
                logs_buffer[buf_pos++] = '"';
                strcpy(logs_buffer + buf_pos, log_to_use);
                buf_pos += log_len;
                logs_buffer[buf_pos++] = '"';
                
                if (escaped_log) {
                    free(escaped_log);
                }
            } else {
                // 缓冲区不足，截断并添加提示
                if (buf_pos + 20 < sizeof(logs_buffer)) {
                    strcpy(logs_buffer + buf_pos, "...(truncated)");
                    buf_pos += strlen("...(truncated)");
                }
                break;
            }
        }
        
        logs_buffer[buf_pos++] = ']';
        logs_buffer[buf_pos] = '\0';
        
        // 转义整个日志数组字符串
        char* escaped_logs = escape_csv(logs_buffer);
        
        // 输出所有字段，确保使用转义后的版本
        fprintf(file, "%s,%s,%s,%u\n", 
                escaped_group_key ? escaped_group_key : (map[i].group_key ? map[i].group_key : ""),
                escaped_template ? escaped_template : (map[i].template_str ? map[i].template_str : ""),
                escaped_logs ? escaped_logs : logs_buffer,
                map[i].log_count);
        
        // 释放转义后的字符串
        if (escaped_group_key) free(escaped_group_key);
        if (escaped_template) free(escaped_template);
        if (escaped_logs) free(escaped_logs);
    }
    
    fclose(file);
    free_template_logs_map(map, template_count);
}

int main(int argc, char* argv[]) {
    if (argc != 2 && argc != 3) {
        printf("Usage: %s <log_file> [output_csv_file]\n", argv[0]);
        printf("Default output file: parsing_results.csv\n");
        return 1;
    }

    const char* input_file = argv[1];
    const char* output_file = (argc == 3) ? argv[2] : "parsing_results.csv";

    FILE* file = fopen(input_file, "r");
    if (!file) {
        perror("Failed to open file");
        return 1;
    }

    printf("Processing log file: %s\n", input_file);
    printf("Output CSV file: %s\n", output_file);
    printf("Start time: %s", ctime(&(time_t){time(NULL)}));

    // 初始化日志记录器
    LogRecords log_records = {0};
    log_records.capacity = 1000;
    log_records.records = malloc(log_records.capacity * sizeof(LogRecord));
    if (!log_records.records) {
        fclose(file);
        printf("Failed to allocate memory for log records\n");
        return 1;
    }

    // 初始化分组管理器
    GroupManager* gm = group_manager_init();
    if (!gm) {
        fclose(file);
        free(log_records.records);
        printf("Failed to initialize group manager\n");
        return 1;
    }

    char* line = NULL;
    size_t len = 0;
    ssize_t read;
    int processed_count = 0;

    while ((read = getline(&line, &len, file)) != -1) {
        // 去除换行符
        if (read > 0 && line[read - 1] == '\n') {
            line[read - 1] = '\0';
        }

        // 预处理日志消息
        char* preprocessed = preprocess_log(line);
        if (!preprocessed) {
            fprintf(stderr, "Preprocessing failed for: %s\n", line);
            continue;
        }

        // 分词
        uint32_t token_count = 0;
        char** tokens = tokenize_string(preprocessed, &token_count);
        if (!tokens) {
            free(preprocessed);
            fprintf(stderr, "Tokenization failed for: %s\n", line);
            continue;
        }

        // 处理分组
        int group_id = group_manager_process(gm, (const char**)tokens, token_count);
        if (group_id < 0) {
            free(preprocessed);
            free_tokens(tokens, token_count);
            fprintf(stderr, "Grouping failed for: %s\n", line);
            continue;
        }

        // 获取分组
        TemplateGroup* group = group_manager_get_group(gm, group_id);
        if (!group) {
            free(preprocessed);
            free_tokens(tokens, token_count);
            fprintf(stderr, "Failed to get group for ID: %d\n", group_id);
            continue;
        }

        // 模板匹配和生成
        GenerationOptions options = generation_options_default();
        int template_index = process_template_generation(gm, group_id, (const char**)tokens, token_count, options);

        if (template_index >= 0) {
            // 记录这条日志的信息
            if (log_records.count >= log_records.capacity) {
                // 扩展容量
                log_records.capacity *= 2;
                LogRecord* new_records = realloc(log_records.records, 
                                                log_records.capacity * sizeof(LogRecord));
                if (!new_records) {
                    fprintf(stderr, "Failed to expand log records capacity\n");
                    break;
                }
                log_records.records = new_records;
            }
            
            // 记录日志信息
            log_records.records[log_records.count].original_log = strdup(line);
            log_records.records[log_records.count].group_id = group_id;
            log_records.records[log_records.count].template_index = template_index;
            log_records.count++;
        } else {
            fprintf(stderr, "Template generation failed for: %s\n", line);
        }

        processed_count++;
        free(preprocessed);
        free_tokens(tokens, token_count);
        
        // 每处理1000行显示进度
        if (processed_count % 1000 == 0) {
            printf("Processed %d log entries...\n", processed_count);
        }
    }

    free(line);
    fclose(file);

    // 输出 CSV 文件
    write_logs_to_csv(gm, &log_records, output_file);
    printf("CSV output saved to %s\n", output_file);
    printf("Processed %d log entries\n", processed_count);
    printf("End time: %s", ctime(&(time_t){time(NULL)}));

    // 释放日志记录器的资源
    for (uint32_t i = 0; i < log_records.count; i++) {
        free(log_records.records[i].original_log);
    }
    free(log_records.records);

    // 释放分组管理器资源
    group_manager_free(gm);

    return 0;
}*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include "preprocess.h"
#include "grouping.h"
#include "matching.h"
#include "generation.h"

// 日志记录结构
typedef struct {
    char* original_log;
    int group_id;
    int template_index;
} LogRecord;

typedef struct {
    LogRecord* records;
    uint32_t count;
    uint32_t capacity;
} LogRecords;

// CSV 转义辅助函数
char* escape_csv(const char* str) {
    if (!str) return NULL;
    
    // 检查是否需要转义（包含逗号、双引号或换行符）
    int needs_escaping = 0;
    for (const char* p = str; *p; p++) {
        if (*p == '"' || *p == ',' || *p == '\n' || *p == '\r') {
            needs_escaping = 1;
            break;
        }
    }
    
    if (!needs_escaping) return NULL;
    
    // 计算需要转义的字符数
    int escape_count = 0;
    for (const char* p = str; *p; p++) {
        if (*p == '"') escape_count++;
    }
    
    // 分配足够的内存（原始长度 + 转义字符数 + 引号）
    char* result = malloc(strlen(str) + escape_count + 3);
    if (!result) return NULL;
    
    char* dst = result;
    *dst++ = '"';
    
    for (const char* p = str; *p; p++) {
        if (*p == '"') {
            *dst++ = '"';
            *dst++ = '"';
        } else {
            *dst++ = *p;
        }
    }
    
    *dst++ = '"';
    *dst = '\0';
    
    return result;
}

// 获取组表中的组数量
uint32_t get_group_table_size(const GroupTable* table) {
    return table->group_count;
}

// 获取指定索引的组
TemplateGroup* get_group_from_table(const GroupTable* table, uint32_t index) {
    if (index >= table->group_count) return NULL;
    return table->groups[index];
}

// 获取模板字符串
const char* get_template_string(const GroupManager* gm, int group_id, int template_index) {
    if (group_id < 0 || group_id >= (int)get_group_table_size(gm->group_table)) {
        return NULL;
    }
    
    TemplateGroup* group = get_group_from_table(gm->group_table, group_id);
    if (!group || template_index < 0 || template_index >= (int)group->template_count) {
        return NULL;
    }
    
    return group->templates[template_index]->template_str;
}

// 获取组键
const char* get_group_key(const GroupManager* gm, int group_id) {
    if (group_id < 0 || group_id >= (int)get_group_table_size(gm->group_table)) {
        return NULL;
    }
    
    TemplateGroup* group = get_group_from_table(gm->group_table, group_id);
    if (!group) {
        return NULL;
    }
    
    return group->group_key;
}

// 输出 CSV 文件 - 修改为一对一格式
void write_logs_to_csv(const GroupManager* gm, const LogRecords* log_records, const char* filename) {
    FILE* file = fopen(filename, "w");
    if (!file) {
        perror("Failed to open CSV file");
        return;
    }
    
    // 写入CSV表头
    fprintf(file, "GroupKey,Template,OriginalLog\n");
    
    // 遍历所有日志记录
    for (uint32_t i = 0; i < log_records->count; i++) {
        const LogRecord* record = &log_records->records[i];
        
        // 获取组键和模板
        const char* group_key = get_group_key(gm, record->group_id);
        const char* template_str = get_template_string(gm, record->group_id, record->template_index);
        
        if (!group_key || !template_str) {
            continue; // 跳过无效记录
        }
        
        // 转义所有字段，确保CSV格式正确
        char* escaped_group_key = escape_csv(group_key);
        char* escaped_template = escape_csv(template_str);
        char* escaped_log = escape_csv(record->original_log);
        
        // 输出所有字段，确保使用转义后的版本
        fprintf(file, "%s,%s,%s\n", 
                escaped_group_key ? escaped_group_key : group_key,
                escaped_template ? escaped_template : template_str,
                escaped_log ? escaped_log : record->original_log);
        
        // 释放转义后的字符串
        if (escaped_group_key) free(escaped_group_key);
        if (escaped_template) free(escaped_template);
        if (escaped_log) free(escaped_log);
    }
    
    fclose(file);
}

int main(int argc, char* argv[]) {
    if (argc != 2 && argc != 3) {
        printf("Usage: %s <log_file> [output_csv_file]\n", argv[0]);
        printf("Default output file: parsing_results.csv\n");
        return 1;
    }

    const char* input_file = argv[1];
    const char* output_file = (argc == 3) ? argv[2] : "parsing_results.csv";

    FILE* file = fopen(input_file, "r");
    if (!file) {
        perror("Failed to open file");
        return 1;
    }

    printf("Processing log file: %s\n", input_file);
    printf("Output CSV file: %s\n", output_file);
    printf("Start time: %s", ctime(&(time_t){time(NULL)}));

    // 初始化日志记录器
    LogRecords log_records = {0};
    log_records.capacity = 1000;
    log_records.records = malloc(log_records.capacity * sizeof(LogRecord));
    if (!log_records.records) {
        fclose(file);
        printf("Failed to allocate memory for log records\n");
        return 1;
    }

    // 初始化分组管理器
    GroupManager* gm = group_manager_init();
    if (!gm) {
        fclose(file);
        free(log_records.records);
        printf("Failed to initialize group manager\n");
        return 1;
    }

    char* line = NULL;
    size_t len = 0;
    ssize_t read;
    int processed_count = 0;

    while ((read = getline(&line, &len, file)) != -1) {
        // 去除换行符
        if (read > 0 && line[read - 1] == '\n') {
            line[read - 1] = '\0';
        }

        // 预处理日志消息
        char* preprocessed = preprocess_log(line);
        if (!preprocessed) {
            fprintf(stderr, "Preprocessing failed for: %s\n", line);
            continue;
        }

        // 分词
        uint32_t token_count = 0;
        char** tokens = tokenize_string(preprocessed, &token_count);
        if (!tokens) {
            free(preprocessed);
            fprintf(stderr, "Tokenization failed for: %s\n", line);
            continue;
        }

        // 处理分组
        int group_id = group_manager_process(gm, (const char**)tokens, token_count);
        if (group_id < 0) {
            free(preprocessed);
            free_tokens(tokens, token_count);
            fprintf(stderr, "Grouping failed for: %s\n", line);
            continue;
        }

        // 获取分组
        TemplateGroup* group = group_manager_get_group(gm, group_id);
        if (!group) {
            free(preprocessed);
            free_tokens(tokens, token_count);
            fprintf(stderr, "Failed to get group for ID: %d\n", group_id);
            continue;
        }

        // 模板匹配和生成
        GenerationOptions options = generation_options_default();
        int template_index = process_template_generation(gm, group_id, (const char**)tokens, token_count, options);

        if (template_index >= 0) {
            // 记录这条日志的信息
            if (log_records.count >= log_records.capacity) {
                // 扩展容量
                log_records.capacity *= 2;
                LogRecord* new_records = realloc(log_records.records, 
                                                log_records.capacity * sizeof(LogRecord));
                if (!new_records) {
                    fprintf(stderr, "Failed to expand log records capacity\n");
                    break;
                }
                log_records.records = new_records;
            }
            
            // 记录日志信息
            log_records.records[log_records.count].original_log = strdup(line);
            log_records.records[log_records.count].group_id = group_id;
            log_records.records[log_records.count].template_index = template_index;
            log_records.count++;
        } else {
            fprintf(stderr, "Template generation failed for: %s\n", line);
        }

        processed_count++;
        free(preprocessed);
        free_tokens(tokens, token_count);
        
        // 每处理1000行显示进度
        if (processed_count % 1000 == 0) {
            printf("Processed %d log entries...\n", processed_count);
        }
    }

    free(line);
    fclose(file);

    // 输出 CSV 文件
    write_logs_to_csv(gm, &log_records, output_file);
    printf("CSV output saved to %s\n", output_file);
    printf("Processed %d log entries\n", processed_count);
    printf("End time: %s", ctime(&(time_t){time(NULL)}));

    // 释放日志记录器的资源
    for (uint32_t i = 0; i < log_records.count; i++) {
        free(log_records.records[i].original_log);
    }
    free(log_records.records);

    // 释放分组管理器资源
    group_manager_free(gm);

    return 0;
}